package com.water.fish

import android.annotation.SuppressLint
import android.content.Context
import android.content.res.TypedArray
import android.graphics.*
import android.util.AttributeSet
import android.util.Log
import android.view.LayoutInflater
import android.view.MotionEvent
import android.widget.FrameLayout
import com.water.fish.widget.FoodView
import com.water.fish.widget.PetView
import com.water.fish.widget.ShoalView
import kotlin.math.pow

/**
 *  Updated by zxn on 2022/5/9.
 */
class SeaLayout : FrameLayout, ISeaLayout {

    companion object {
        private const val TAG = "SeaLayout"
        private const val MAX_FOOD_COUNT = 5
    }

    private var fallFoodCount = 0

    private var totalFallCount = 0

    private val petView by lazy {
        findViewById<PetView>(R.id.petView)
    }

    private val shoalView by lazy {
        findViewById<ShoalView>(R.id.shoalView)
    }

    private val fishEntityList = mutableListOf<FishEntity>()

    /**
     * 鱼儿游动范围左边Padding
     */
    private var paddingPetAreaLeft = 0

    /**
     * 停止动画标识.
     */
    private var isEnd = false

    private var isStarted = false

    private var mPetDragEnabled = false

    var petFeeding = false

    private var isStartFeed = false

    /**
     * 轨迹类型:0:固定,1:随机.默认固定.
     */
    private var trailType = 0

    //private var mWidth = 0
    private var mHeight = 0

    private val foodViewList = mutableListOf<FoodView>()

    private var foodWith = 90

    private var foodHeight = 70

    private var mLastX = 0F

    private var mLastY = 0F

    //每一笔的最后一个图的index，所以：这个List.size = 一共几笔
    private val strokeFirstPositionArray = mutableListOf<Int>()

    //连续两个礼物之间的间距（像素），0表示用当前礼物的宽
    private val drawStrokeInterval = 0


    /**
     * 单词滑动屏幕的,出现的食物数目限制.
     */
    var maxFoodCount = MAX_FOOD_COUNT

    /**
     * 洒落食物监听
     */
    private var mFeedListener: ((SeaLayout, MutableList<FoodView>) -> Unit)? = null

    constructor(context: Context) : this(context, null)

    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int = 0) : super(
        context,
        attrs,
        defStyleAttr
    ) {
        setWillNotDraw(false)
        setBackgroundColor(Color.TRANSPARENT)
        LayoutInflater.from(context).inflate(R.layout.layout_sea_content, this)
        onInitAttributeSet(attrs)
        petView.let {
            it.dragEnabled = mPetDragEnabled
            it.trailType = trailType
        }
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        Log.i(TAG, "onSizeChanged: ")

        petView.onInitMovement(RectF().apply {
            left = (paddingLeft + paddingPetAreaLeft).toFloat()
            top = paddingTop.toFloat()
            right = width - paddingRight.toFloat() - petView.measuredWidth
            bottom =
                height - paddingBottom.toFloat() - (petView.layoutParams as LayoutParams).bottomMargin - petView.measuredHeight
        })

        shoalView.onInitMovement(RectF().apply {
            left = paddingLeft.toFloat()
            top =
                (height - paddingBottom - shoalView.measuredHeight - (shoalView.layoutParams as LayoutParams).bottomMargin * 2).toFloat()
            right = (width - paddingRight).toFloat()
            bottom = (height - paddingBottom).toFloat()
        })

        if (h != oldh) {
            //mWidth = w
            mHeight = h
        }
    }

    override fun notifyDataSetChanged(position: Int) {
        when (position) {
            0 -> petView.onChanged(fishEntityList[0])
            1 -> shoalView.onChanged(fishEntityList[1])
        }
    }

    override fun notifyDataSetChanged() {
        fishEntityList.forEachIndexed { _, entity ->
            when (entity) {
                is PetFish -> petView.onChanged(entity)
                is ShoalFish -> shoalView.onChanged(entity)
            }
        }
    }

    override fun setFishData(entityList: MutableList<FishEntity>) {
        if (entityList.isNullOrEmpty()) throw IllegalStateException("entityList can not be null or empty !")

        end()

        if (entityList !== fishEntityList) {
            fishEntityList.clear()
            fishEntityList.addAll(entityList)
        } else {
            val newList = ArrayList(entityList)
            fishEntityList.clear()
            fishEntityList.addAll(newList)
        }

        notifyDataSetChanged()

    }

    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent): Boolean {
        Log.i(TAG, "onTouchEvent: ${event.action}")
        return if (petFeeding) touchFeeding(event) else petView.touchMoveByParent(event)
    }

    /**
     * 重写此函数绘制其子view.
     */
    override fun dispatchDraw(canvas: Canvas) {
        super.dispatchDraw(canvas)
    }

    /**
     * 触摸任意位置并洒落鱼食物.
     * @param event 触摸事件.
     */
    private fun touchFeeding(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                if (isFeedFalling()) return false
                //点下
                mLastX = checkIfBelongHorizontalEdge(event.x)
                mLastY = checkIfBelongVerticalEdge(event.y)
                addFoodView(mLastX, mLastY)

                //记录这一笔的开头
                strokeFirstPositionArray.add(foodViewList.size - 1)
            }
            MotionEvent.ACTION_MOVE -> {
                if (isFeedFalling()) return false
                val moveX = checkIfBelongHorizontalEdge(event.x)
                val moveY = checkIfBelongVerticalEdge(event.y)

                //距离上一个礼物的移动距离
                val distance = ((moveX - mLastX).toDouble().pow(2.0) + (moveY - mLastY).toDouble()
                    .pow(2.0)).toFloat()

                //理应移动多少才需要画新礼物
                val reference =
                    (if (drawStrokeInterval == 0) foodWith * 80 else drawStrokeInterval.toDouble()
                        .pow(2.0)).toFloat()

                if (distance >= reference) {
                    //距离拉开了，应该画新礼物
                    if (moveX >= left && moveX < right && moveY >= top && moveY < bottom) {
                        if (foodViewList.size < maxFoodCount) {
                            //看看新礼物是否在View内
                            addFoodView(moveX, moveY)
                            mLastX = moveX
                            mLastY = moveY
                            /*if (onDrawGiftListener != null) {
                                onDrawGiftListener.onGiftPainted(this, currentGiftId)
                            }*/
                        }
                    } else {
                        //越界
                    }
                }
            }
            MotionEvent.ACTION_UP -> {
                //喂食进行中.
                if (isFeedFalling()) return false

                fallFoodCount = 0
                totalFallCount = foodViewList.size
                isStartFeed = true
                for (v in foodViewList) {
                    addView(v, foodWith, foodHeight)
                    v.fall(mHeight.toFloat()) {
                        removeView(it)
                        fallFoodCount++
                    }
                }
                mFeedListener?.invoke(this, foodViewList)

                if (foodViewList.isNotEmpty()) {
                    //petView.feed(foodViewList.last())
                    petView.feed(foodViewList)
                }
                foodViewList.clear()
            }
            MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_OUTSIDE, MotionEvent.ACTION_POINTER_DOWN -> {

            }
        }
        return if (maxFoodCount <= 0) super.onTouchEvent(event) else true
    }

    private fun onInitAttributeSet(attrs: AttributeSet?) {
        val typedArray: TypedArray =
            context.obtainStyledAttributes(attrs, R.styleable.SeaLayout)
        try {
            paddingPetAreaLeft =
                typedArray.getDimensionPixelOffset(
                    R.styleable.SeaLayout_paddingPetAreaLeft,
                    0
                )
            //autoplay = typedArray.getBoolean(R.styleable.SeaLayout_pet_autoplay, true)
            mPetDragEnabled = typedArray.getBoolean(R.styleable.SeaLayout_pet_dragEnabled, false)
            trailType = typedArray.getInt(R.styleable.SeaLayout_pet_trailType, 0)
            petFeeding = typedArray.getBoolean(R.styleable.SeaLayout_pet_feeding, false)
            foodWith =
                typedArray.getDimensionPixelOffset(
                    R.styleable.SeaLayout_foodWith,
                    90
                )
            foodHeight =
                typedArray.getDimensionPixelOffset(
                    R.styleable.SeaLayout_foodHeight,
                    70
                )
        } finally {
            typedArray.recycle()
        }
    }

    private fun addFoodView(x: Float, y: Float) {
        foodViewList.add(FoodView(context).apply {
            translationX = x
            translationY = y
        })
    }

    /**
     * 横向检查是否是屏幕边缘
     */
    private fun checkIfBelongHorizontalEdge(intrinsicX: Float): Float =
        when {
            //超过左边界
            intrinsicX > width - foodWith / 2F -> width - foodWith / 2F
            //超过右边界
            intrinsicX < foodWith / 2F -> foodWith / 2F

            else -> intrinsicX
        }

    /**
     * 纵向检查是否是屏幕边缘
     */
    private fun checkIfBelongVerticalEdge(intrinsicY: Float): Float =
        when {

            //超过右边界
            intrinsicY > height - foodWith / 2F -> height - foodWith / 2F

            //超过左边界
            intrinsicY < foodWith / 2F -> foodWith / 2F

            else -> intrinsicY
        }

    /**
     * 手指抬起,洒落食物后的监听
     */
    fun feedListener(block: ((SeaLayout, MutableList<FoodView>) -> Unit)) {
        mFeedListener = block
    }

    /**
     * 吃到食物的监听.
     */
    fun eatFoodListener(block: (() -> Unit)) {
        petView.eatListener(block)
    }

    /**
     * 食物正在洒落中.
     */
    fun isFeedFalling(): Boolean = (fallFoodCount != totalFallCount && totalFallCount > 0)

    /**
     * 标记结束函数
     */
    fun end() {
        isStarted = false
        isEnd = true
    }

    /**
     * 宠物顶部文字提示.
     */
    fun tips() {
        petView.tips()
    }

    /**
     * 手指控制宠物轨迹的监听.
     */
    fun touchMoveEndListener(block: () -> Unit) {
        petView.petMoveEndListener(block)
    }

    /**
     * 宠物状态变化监听
     */
    fun petChangeListener(block: (PetFish, PetView, PetAction) -> Unit) {
        petView.petChangeListener(block)
    }

    /**
     * 鱼群转身变化监听
     */
    fun shoalChangeListener(block: (ShoalView) -> Unit) {
        shoalView.shoalChangeListener(block)
    }

    /**
     * 宠物点击监听
     */
    fun setOnPetClickListener(l: OnClickListener?) {
        petView.setOnPetClickListener(l)
    }

}